
// -----------------------------------------------------------------------------

#pragma once

#include "Win32.String.h"
#include "Win32.IO.IStream.h"
#include "xmllite.h"

namespace Kif
{
namespace Win32
{
namespace Xml
{

class XmlNodeAttribute
{
   public:
   HRESULT lastHResult;

   bool Succeeded;

   Kif::Win32::String ErrorMessage;
   Kif::Win32::String Value;

   bool Compare(TCHAR *value)
   {
      return Value.Compare(value) == 0;
   }

   inline bool ToBoolean()
   {
      static TCHAR trueText[] = L"true";
      Value.ToLower();
      return Value.Compare((TCHAR*)trueText) == 0;
   }
}  ;  // end of XmlNodeAttribute

class XmlNodeReference
{
   public:

   HRESULT lastHResult;
   XmlNodeType LastReadNodeType;

   bool Succeeded;  // true if node was read successfully...

   const wchar_t *pErrorMessage;
   const wchar_t *pPrefix;
   const wchar_t *pName;
   const wchar_t *pValue;

   inline void ClearFields()
   {
      pErrorMessage = pPrefix = pName = pValue = NULL;
      Succeeded = false;
      lastHResult = NULL;
   }

   inline Kif::Win32::String *GetErrorMessage(Kif::Win32::String *value)
   {
      if (!value)
         value = new Kif::Win32::String();
      value->Copy((wchar_t*)pErrorMessage);
   }  // end of GetErrorMessage

   inline Kif::Win32::String *GetPrefix(Kif::Win32::String *value)
   {
      if (!value)
         value = new Kif::Win32::String();
      value->Copy((wchar_t*)pPrefix);
   }  // end of GetPrefix

   inline Kif::Win32::String *GetName(Kif::Win32::String *value)
   {
      if (!value)
         value = new Kif::Win32::String();
      value->Copy((wchar_t*)pName);
   }  // end of GetName

   inline Kif::Win32::String *GetValue(Kif::Win32::String *value)
   {
      if (!value)
         value = new Kif::Win32::String();
      value->Copy((wchar_t*)pValue);
   }  // end of GetValue

   XmlNodeReference()
   {
      ClearFields();
   }

   bool Compare(wchar_t *value)
   {
      return Kif::Win32::String::Compare(value,(wchar_t *)pName) == 0;
   }
}  ;  // end of XmlNodeReference

class XmlNode
{
   public:

   XmlNodeReference NodeReference;

   Kif::Win32::String ErrorMessage;
   Kif::Win32::String Prefix;
   Kif::Win32::String Name;
   Kif::Win32::String Value;

   bool Succeeded()
   {
      return NodeReference.Succeeded;
   }

   inline void ClearFields()
   {
      NodeReference.ClearFields();
      ErrorMessage.Dispose();
      Name.Dispose();
      Value.Dispose();
   }

   inline void CopyReferenceData()
   {
      if (NodeReference.pErrorMessage)
         ErrorMessage.Copy((wchar_t*)NodeReference.pErrorMessage);
      else
         ErrorMessage.Dispose();

      if (NodeReference.pPrefix)
         Prefix.Copy((wchar_t*)NodeReference.pPrefix);
      else
         Prefix.Dispose();

      if (NodeReference.pName)
         Name.Copy((wchar_t*)NodeReference.pName);
      else
         Name.Dispose();

      if (NodeReference.pValue)
         Value.Copy((wchar_t*)NodeReference.pValue);
      else
         Value.Dispose();
   }  // end of CopyReferenceData

   XmlNode()
   {
      ClearFields();
   }

   bool Compare(TCHAR *value)
   {
      return Name.Compare(value) == 0;
   }
}  ;  // end of XmlNode

class XmlLiteReader
{
   private:
   HRESULT lastHResult;
   CComPtr<IXmlReader> pReader;

   Kif::Win32::IO::StreamTextReader strTextReader;
   XmlLiteReader *CreateXmlReader(TCHAR *filePath);

   bool ReadElement(XmlNodeReference &node);
   bool ReadProcessingInstruction(XmlNodeReference &node);

   /// <summary>Read value node.</summary>
   /// <param name="node">node reference info read</param>
   /// <returns>true is returned if reading should move to next element or
   /// an error was found to allow caller to handle it</returns>
   inline bool ReadValue(XmlNodeReference &node)
   {
      const wchar_t *pValue;
      if (FAILED(lastHResult = pReader->GetValue(&pValue,NULL)))                     
      {
         node.pErrorMessage = L"Error reading value";
         return true;
      }

      if (lastHResult == S_OK)
      {
         node.pValue = pValue;
         node.Succeeded = true;
      }

      return true;
   }  // end of ReadValue

   public:

   bool ReadQualifiedName;           // true [to read namespace:tag] (default)
   bool ReadProcessingInstructions;  // false to skip / ignore (default)
   bool ReadComments;                // false to skip / ignore (default)
   bool ReadEndElement;              // false to skip / ignore (default)

   void Init()
   {
      lastHResult = NULL;
      ReadComments = ReadProcessingInstructions = ReadEndElement = false;
      ReadQualifiedName = true;
   }

   XmlLiteReader(TCHAR *filePath)
   {
      Init();
      CreateXmlReader(filePath);
   }  // end of XmlLiteReader (ctor)

   XmlLiteReader(Kif::Win32::String &filePath)
   {
      Init();
      CreateXmlReader(filePath.GetBuffer());
   }  // end of XmlLiteReader (ctor)

   XmlLiteReader(Kif::Win32::String *filePath)
   {
      Init();
      CreateXmlReader(filePath->GetBuffer());
   }  // end of XmlLiteReader (ctor)

   XmlNodeAttribute *ReadAttributeValue(
      TCHAR *attributeName, XmlNodeAttribute &attribute);

   XmlNodeReference *Read(XmlNodeReference &node);

   inline XmlNode *Read(XmlNode &node)
   {
      Read(node.NodeReference);
      node.CopyReferenceData();
      return &node;
   }  // end of Read

}  ;  // end of XmlLiteReader

}  // end of Kif::Win32::Xml namespace
}  // end of Kif::Win32 namespace
}  // end of Kif namespace
